﻿
/******************************************************
* author :  jilonglv
* email  : jilonglv@gmail.com
* function:
* history:  created by jilonglv 2020/10/14 11:30:10
* clrversion :4.0.30319.42000
******************************************************/

namespace Commnunications
{
    using System;
    using System.Collections;
    using System.Linq;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;

    public static class HeapByteBufferHelper
    {
#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static byte GetByte(byte[] memory, int index) => memory[index];
#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static short GetShort(byte[] memory, int index) =>
            unchecked((short)(memory[index] << 8 | memory[index + 1]));
#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static short GetShortLE(byte[] memory, int index) =>
            unchecked((short)(memory[index] | memory[index + 1] << 8));
#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static short GetUshort(byte[] memory, int index) =>
            unchecked((short)(memory[index] << 8 | memory[index + 1]));
#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static short GetUshortLE(byte[] memory, int index) =>
            unchecked((short)(memory[index] | memory[index + 1] << 8));
#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static int GetUnsignedMedium(byte[] memory, int index) =>
            unchecked(
                memory[index] << 16 |
                memory[index + 1] << 8 |
                memory[index + 2]);

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static int GetUnsignedMediumLE(byte[] memory, int index) =>
            unchecked(
                memory[index] |
                memory[index + 1] << 8 |
                memory[index + 2] << 16);

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static int GetInt(byte[] memory, int index) =>
            unchecked(
                memory[index] << 24 |
                memory[index + 1] << 16 |
                memory[index + 2] << 8 |
                memory[index + 3]);

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static int GetIntLE(byte[] memory, int index) =>
            unchecked(
                memory[index] |
                memory[index + 1] << 8 |
                memory[index + 2] << 16 |
                memory[index + 3] << 24);

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static long GetLong(byte[] memory, int index) =>
            unchecked(
                (long)memory[index] << 56 |
                (long)memory[index + 1] << 48 |
                (long)memory[index + 2] << 40 |
                (long)memory[index + 3] << 32 |
                (long)memory[index + 4] << 24 |
                (long)memory[index + 5] << 16 |
                (long)memory[index + 6] << 8 |
                memory[index + 7]);

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static long GetLongLE(byte[] memory, int index) =>
            unchecked(
                memory[index] |
                (long)memory[index + 1] << 8 |
                (long)memory[index + 2] << 16 |
                (long)memory[index + 3] << 24 |
                (long)memory[index + 4] << 32 |
                (long)memory[index + 5] << 40 |
                (long)memory[index + 6] << 48 |
                (long)memory[index + 7] << 56);

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetByte(byte[] memory, int index, int value)
        {
            unchecked
            {
                memory[index] = (byte)value;
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetShort(byte[] memory, int index, int value)
        {
            unchecked
            {
                memory[index] = (byte)((ushort)value >> 8);
                memory[index + 1] = (byte)value;
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetShortLE(byte[] memory, int index, int value)
        {
            unchecked
            {
                memory[index] = (byte)value;
                memory[index + 1] = (byte)((ushort)value >> 8);
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetMedium(byte[] memory, int index, int value)
        {
            unchecked
            {
                uint unsignedValue = (uint)value;
                memory[index] = (byte)(unsignedValue >> 16);
                memory[index + 1] = (byte)(unsignedValue >> 8);
                memory[index + 2] = (byte)unsignedValue;
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetMediumLE(byte[] memory, int index, int value)
        {
            unchecked
            {
                uint unsignedValue = (uint)value;
                memory[index] = (byte)unsignedValue;
                memory[index + 1] = (byte)(unsignedValue >> 8);
                memory[index + 2] = (byte)(unsignedValue >> 16);
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetInt(byte[] memory, int index, int value)
        {
            unchecked
            {
                uint unsignedValue = (uint)value;
                memory[index] = (byte)(unsignedValue >> 24);
                memory[index + 1] = (byte)(unsignedValue >> 16);
                memory[index + 2] = (byte)(unsignedValue >> 8);
                memory[index + 3] = (byte)unsignedValue;
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetIntLE(byte[] memory, int index, int value)
        {
            unchecked
            {
                uint unsignedValue = (uint)value;
                memory[index] = (byte)unsignedValue;
                memory[index + 1] = (byte)(unsignedValue >> 8);
                memory[index + 2] = (byte)(unsignedValue >> 16);
                memory[index + 3] = (byte)(unsignedValue >> 24);
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetLong(byte[] memory, int index, long value)
        {
            unchecked
            {
                ulong unsignedValue = (ulong)value;
                memory[index] = (byte)(unsignedValue >> 56);
                memory[index + 1] = (byte)(unsignedValue >> 48);
                memory[index + 2] = (byte)(unsignedValue >> 40);
                memory[index + 3] = (byte)(unsignedValue >> 32);
                memory[index + 4] = (byte)(unsignedValue >> 24);
                memory[index + 5] = (byte)(unsignedValue >> 16);
                memory[index + 6] = (byte)(unsignedValue >> 8);
                memory[index + 7] = (byte)unsignedValue;
            }
        }

#if !NET40
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
        public static void SetLongLE(byte[] memory, int index, long value)
        {
            unchecked
            {
                ulong unsignedValue = (ulong)value;
                memory[index] = (byte)unsignedValue;
                memory[index + 1] = (byte)(unsignedValue >> 8);
                memory[index + 2] = (byte)(unsignedValue >> 16);
                memory[index + 3] = (byte)(unsignedValue >> 24);
                memory[index + 4] = (byte)(unsignedValue >> 32);
                memory[index + 5] = (byte)(unsignedValue >> 40);
                memory[index + 6] = (byte)(unsignedValue >> 48);
                memory[index + 7] = (byte)(unsignedValue >> 56);
            }
        }

        public static int Reverse(int source)
        {
            unchecked
            {
                uint unsignedValue = (uint)source;
                return BitConverter.ToInt32(new byte[]{ (byte)(unsignedValue >> 24),
                     (byte)(unsignedValue >> 16),
                     (byte)(unsignedValue >> 8),
                     (byte)unsignedValue }, 0);
            }
        }
        public static short Reverse(short value)
        {
            unchecked
            {
                return BitConverter.ToInt16(new byte[]{ (byte)((ushort)value >> 8),
                     (byte)value }, 0);
            }
        }
        public static uint Reverse(uint source)
        {
            unchecked
            {
                uint unsignedValue = (uint)source;
                return BitConverter.ToUInt32(new byte[]{ (byte)(unsignedValue >> 24),
                     (byte)(unsignedValue >> 16),
                     (byte)(unsignedValue >> 8),
                     (byte)unsignedValue }, 0);
            }
        }
        public static ushort Reverse(ushort value)
        {
            unchecked
            {
                return BitConverter.ToUInt16(new byte[]{ (byte)((ushort)value >> 8),
                     (byte)value }, 0);
            }
        }

        public static T UnpackData<T>(byte[] buffer)
        {
            int offset = 0;
            return UnpackData<T>(buffer, ref offset);
        }
        public static T UnpackData<T>(byte[] buffer, ref int offset)
        {
            try
            {
                var size = Marshal.SizeOf(typeof(T));
                byte[] bufferObj = new byte[size];
                //int len = socket.Receive(buffer, size, SocketFlags.None);
                Array.Copy(buffer, offset, bufferObj, 0, size);
                T data = (T)BytesToStuct(bufferObj, typeof(T));
                offset += size;
                return data;
            }
            catch (Exception)
            {
                return default(T);
            }
        }
        /// <summary>
        /// byte数组转结构体
        /// </summary>
        /// <param name="bytes">byte数组</param>
        /// <param name="type">结构体类型</param>
        /// <returns>转换后的结构体</returns>
        static object BytesToStuct(byte[] bytes, Type type)
        {
            //得到结构体的大小
            int size = Marshal.SizeOf(type);
            //byte数组长度小于结构体的大小
            if (size > bytes.Length)
            {
                //返回空
                return null;
            }
            //分配结构体大小的内存空间
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷到分配好的内存空间
            try
            {
                Marshal.Copy(bytes, 0, structPtr, size);
                //将内存空间转换为目标结构体
                object obj = Marshal.PtrToStructure(structPtr, type);
                return obj;
            }
            catch (Exception)
            {
            }
            finally
            {
                //释放内存空间
                Marshal.FreeHGlobal(structPtr);
            }
            //返回结构体
            return null;
        }
        public static byte[] SkipTake(byte[] buffer, int offset, int len)
        {
            return buffer.Skip(offset).Take(len).ToArray();
        }
        public static int PayloadInt(this CommandBuilder builder, int value)
        {
            var buffer = new byte[4];
            SetInt(buffer, 0, value);
            return builder.Payload(buffer);
        }
        public static int PayloadIntLE(this CommandBuilder builder, int value)
        {
            var buffer = new byte[4];
            SetIntLE(buffer, 0, value);
            return builder.Payload(buffer);
        }
        public static int PayloadShort(this CommandBuilder builder, int value)
        {
            var buffer = new byte[2];
            SetShort(buffer, 0, value);
            return builder.Payload(buffer);
        }
        public static int PayloadShortLE(this CommandBuilder builder, int value)
        {
            var buffer = new byte[2];
            SetShortLE(buffer, 0, value);
            return builder.Payload(buffer);
        }
    }
}
